#include "project_config.h"

#if (CMD_GPIO_TEST == 1)
#include "qelib.h"

static qe_const_str usages[] = {
    "gpio [options] [[--] args]",
    "gpio [options]",
    QE_NULL,
};

static char current_device[32] = {'\0'};

static qe_ret action_list_gpio_devices(qe_argparse *parser, qe_option *option)
{
    qe_gpio_list_devices();
    qe_printf("current gpio device %s\r\n", current_device);
    return qe_yield;
}

static qe_ret action_set_current_device(qe_argparse *parser, qe_option *option)
{
    qe_sprintf(current_device, "%s", qe_option_string(option));
    qe_printf("set current gpio device %s\r\n", current_device);
    return qe_yield;
}

static qe_ret action_dump_gpio_registers(qe_argparse *parser, qe_option *option)
{
    qe_dev *dev = qe_dev_find(current_device);
    if (!dev) {
        qe_printf("no such device %s\r\n", current_device);
        return qe_yield;
    }

    qe_dev_ioctl(dev, QE_GPIO_IOC_DUMP_REGISTERS, QE_NULL);
    return qe_yield;
}

static qe_ret action_list_gpio_pins(qe_argparse *parser, qe_option *option)
{
    qe_dev *dev = qe_dev_find(current_device);
    if (!dev) {
        qe_printf("no such device %s\r\n", current_device);
        return qe_yield;
    }

    qe_dev_ioctl(dev, QE_GPIO_IOC_LIST_PINS, QE_NULL);
    return qe_yield;
}

static qe_ret cmd_gpio_get_value(qe_argparse *parser, qe_option *option)
{
    qe_ret ret;
    qe_uint pin = 0;
    qe_uint value = 0;
    qe_argparse subparser;

    qe_gpio_dev *dev = (qe_gpio_dev *)qe_dev_find(current_device);
    if (!dev) {
        qe_printf("no such device %s\r\n", current_device);
        return qe_yield;
    }

    qe_option options[] = {
        QE_OPT_INTEGER('p', "pin", "set pin number", &pin),
        QE_OPT_HELP('h', "--help", "gpio help"),
        QE_OPT_END(),
    };

    qe_argp_init(&subparser, options, usages,
        "\ngpio value command.", 
        "\ngpio value command end.");
    ret = qe_argp_parse(&subparser, parser->argc, parser->argv);
    if (ret != qe_ok) {
        return qe_yield;
    }

    value = qe_gpio_get_value(dev, pin);
    qe_printf("%s pin:%d value:%d\r\n", current_device, pin, value);
    return qe_yield;
}

static qe_ret cmd_gpio_set_direct(qe_argparse *parser, qe_option *option)
{
    qe_ret ret;
    qe_uint pin = 0;
    qe_uint value = 0;
    qe_bool is_input = qe_false;
    qe_argparse subparser;

    qe_gpio_dev *dev = (qe_gpio_dev *)qe_dev_find(current_device);
    if (!dev) {
        qe_printf("no such device %s\r\n", current_device);
        return qe_yield;
    }

    qe_option options[] = {
        QE_OPT_INTEGER('p', "pin", "set pin number", &pin),
        QE_OPT_INTEGER('v', "val", "set pin value", &value),
        QE_OPT_TRUE('i', "input", "set direction input", &is_input),
        QE_OPT_FALSE('o', "output", "set direction output", &is_input),
        QE_OPT_HELP('h', "--help", "gpio help"),
        QE_OPT_END(),
    };

    qe_argp_init(&subparser, options, usages,
        "\ngpio direct command.", 
        "\ngpio direct command end.");
    ret = qe_argp_parse(&subparser, parser->argc, parser->argv);
    if (ret != qe_ok) {
        return qe_yield;
    }

    if (is_input) {
        ret = qe_gpio_direction_input(dev, pin);
        if (ret != qe_ok) {
            qe_printf("%s pin:%d set input err:%d\r\n", current_device, pin, ret);
            return qe_yield;
        }
        qe_printf("%s pin:%d set input\r\n", current_device, pin);
    } else {
        ret = qe_gpio_direction_output(dev, pin, value);
        if (ret != qe_ok) {
            qe_printf("%s pin:%d set output err:%d\r\n", current_device, pin, ret);
            return qe_yield;
        }
        qe_printf("%s pin:%d set output %d\r\n", current_device, pin, value);
    }

    return qe_yield;
}

static void cmd_gpio(int argc, char *argv[])
{
    qe_ret ret;
    qe_str name;
    qe_argparse parser;
    qe_dev *dev;

    qe_option options[] = {
        QE_OPT_ACTION('l', "list", "list gpio devices",
            QE_NULL, action_list_gpio_devices),
        QE_ACT_STRING('d', "dev", "set current gpio devices",
            &name, QE_NULL, action_set_current_device),
        QE_OPT_ACTION('r', "regs", "dump gpio device registers",
            QE_NULL, action_dump_gpio_registers),
        QE_OPT_ACTION(QE_NULL, "list-pins", "list gpio pins",
            QE_NULL, action_list_gpio_pins),
        QE_OPT_SUBCMD("getval", "get value",
        	QE_NULL, cmd_gpio_get_value),
        QE_OPT_SUBCMD("direct", "set direction input",
        	QE_NULL, cmd_gpio_set_direct),
        QE_OPT_HELP('h', "--help", "gpio help"),
        QE_OPT_END(),
    };

    qe_argp_init(&parser, options, usages,
    	"\ngpio command.",
		"\ngpio command.");

    ret = qe_argp_parse(&parser, argc, (qe_const_str *)argv);
    if (ret != qe_ok) {
        return;
    }

    dev = qe_dev_find(current_device);
    if (dev) {
        qe_dev_ioctl(dev, QE_GPIO_IOC_SHOW, QE_NULL);
    }
}
QE_SHELL_EXPORT_CMD_EXEC(gpio, cmd_gpio, gpio commands);
#endif
